
/****************************************************************************
**
** Copyright (C) 2004-2008 VATATA.com . All rights reserved.
**
** This file is the part of the Miniutil Poject of VATATA.com.
** Vatata's miniutil library is lightweight and portable (for linux
** and Windows). The C++ Class Library included Threadpool, Dll danymic loading, 
** General socket application model and tcp server, httpserver/servlet, etc. 
** It is a pratical utility disigned for who don't want learn the Big C++ 
** Developing Platform, such as  Boost or ACE.
**
** This file may be used under the terms of the GNU General Public
** License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file.  Alternatively you may (at
** your option) use any later version of the GNU General Public
** License if such license has been publicly approved by VATATA.com.
** (or its successors, if any) and the Miniutil Project Aministrators. 
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://www.gnu.org/licenses/lgpl.html. If you are unsure which 
** license is appropriate for your use, please review the following 
** information: http://code.google.com/p/miniutil/ or contact 
** http://www.vatata.com.
**
** In addition, as a special exception, VATATA.com, as the sole
** copyright holder for Miniutil Project, grants users of VATATA
** P2P Platform the right to release and package with the related 
** libraries without the source code.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. vatata reserves all rights not expressly
** granted herein.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/



#include "miniutil/dll.h"
#include "miniutil/diru.h"
#include "miniutil/log.h"

using namespace miniutil::dll;

std::map<std::string, library *> library::dllMap;

library::library( const char * path) : p_dll(NULL), s_path(path)
{
#ifdef WIN32
	p_dll = LoadLibrary( path );
	if ( p_dll == NULL )
	{
        DWORD err = ::GetLastError();
        M_DEBUG( "LoadLibrary %s failed : %x\n", path, err );
		size_t l = s_path.find_last_of(".");
		if ( l == string::npos )
			s_path += ".dll";
		else
			s_path = s_path.substr(0,l) + ".dll";

		p_dll = LoadLibrary( s_path.c_str() );
	}
#else
	p_dll = dlopen( path , RTLD_LAZY);
	if ( p_dll == NULL  )
	{
		unsigned int l = s_path.find_last_of(".");
		if ( l == string::npos )
			s_path += ".so";
		else
			s_path = s_path.substr(0,l) + ".so";

		p_dll = dlopen( s_path.c_str() , RTLD_LAZY);
	}
	
	if ( ! p_dll )
		M_DEBUG( " load dll %s meet error %s\r\n", path, dlerror() );
#endif
	if ( p_dll )
	{
		dllMap[path] = this;
	}
}

library::~library()
{
//	return;

	if ( p_dll )
	{
		dllMap[s_path] = NULL;
#ifdef WIN32
		FreeLibrary( p_dll );
#else
		dlclose( p_dll );
#endif
	}

	p_dll = NULL;

}

const char * miniutil::dll::INIT_FUNC_NAME = "miniutil_dll_init" ;

library * library::getDll( const char * path, const char * cfg )
{
	std::string spath = miniutil::diru::getAbsolutePathByModule( path );

	library * plib = dllMap[spath] ;

	if ( plib != NULL && plib->p_dll != NULL )
		return plib;

	if ( plib != NULL && plib->p_dll == NULL )
		delete plib;

	plib = new library( path );

	if ( plib->p_dll != NULL )
	{
		dll_init_t d_init = (dll_init_t) plib->getFunc( miniutil::dll::INIT_FUNC_NAME );
		if ( d_init )
			d_init( cfg );
		return plib;
	}

	delete plib;
	return NULL;
}

funcPtr library::getFunc( const char * funcName )
{
#ifdef WIN32
	return GetProcAddress(this->p_dll, funcName); 
#else
	dlerror();
	funcPtr p = dlsym(this->p_dll, funcName); 
	const char *dlsym_error = dlerror();
	if (dlsym_error) 
	{
		M_DEBUG( " load function %s meet error %s\r\n", funcName, (dlsym_error) );
		return NULL;
	}
	return p;
#endif
}
